#include "includes.h"
#define PROTOCOL_PORT 8000

static unsigned char sn = 0;
static unsigned char cur_sn;
static int sockfd;

//int udp_get_packet(char *buf, int buf_len, struct sockaddr *addr);
//void udp_send_packet(const char *tx_buf, const size_t tlen, const struct sockaddr *tx_addr);

int init_communication_protocol()
{
	struct sockaddr_in servaddr;
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(PROTOCOL_PORT);
	sockfd = Socket(AF_INET,SOCK_DGRAM, 0);
	Bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr));
	return 0;
}

static int send_packet(const char *packet_addr, int packet_len)
{
	struct sockaddr_in sendaddr;
	char guest_addr[20];
	local_get_guest_addr(guest_addr, sizeof(guest_addr));
	bzero(&sendaddr, sizeof(sendaddr));
	sendaddr.sin_family = AF_INET;
	Inet_pton(AF_INET, (const char *)guest_addr, (void *)&sendaddr.sin_addr);
	//sendaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	sendaddr.sin_port = htons(PROTOCOL_PORT);
	Sendto(sockfd, (const void *)packet_addr, packet_len, 0, (struct sockaddr *)&sendaddr, sizeof(struct sockaddr));
	return 0;
}
//timeout s
static int recv_packet(char *recv_buff, int buff_len, int timeout)
{
	fd_set readfds;
	struct timeval time_value;
	struct sockaddr_in cliaddr;
	int ret;
	int addr_len;
	int len = 0;

	addr_len = sizeof(struct sockaddr);

	time_value.tv_sec = timeout;
	time_value.tv_usec = 0;

	FD_ZERO(&readfds);
	FD_SET(sockfd, &readfds);
	ret = Select(sockfd+1, &readfds, NULL, NULL, &time_value);
	if (ret == 0)
	{
		err_msg("the communication potocol is time out!");
		return 0;
	}
	if (FD_ISSET(sockfd, &readfds))
	{
		len = Recvfrom(sockfd, (void *)recv_buff, buff_len, 0, (struct sockaddr *)&cliaddr, (socklen_t *)&addr_len);
	}
	return len;
}

int send_request_packet(unsigned char content, char *data, int data_len)
{
	char *buff;
	PS_PACKET_DATA pstPacket;
	int packet_len;
	if (!data)
		data_len = 0;
	packet_len = data_len + sizeof(S_PACKET_DATA);
	buff = Malloc(packet_len);
	bzero(buff, packet_len);
	pstPacket = (PS_PACKET_DATA)buff;
	pstPacket->type = TYPE_REQUEST;
	pstPacket->content = content;
	pstPacket->sn = sn;
	pstPacket->data_len = data_len;
	cur_sn = sn++;
	if (data)
		memcpy(pstPacket->data, data, data_len);
	send_packet(buff, packet_len);
	free(buff);
	return 0;
}

int send_ack_ack_packet(unsigned char content)
{
	char *buff;
	PS_PACKET_DATA pstPacket;
	int packet_len;

	packet_len = sizeof(S_PACKET_DATA);
	buff = Malloc(packet_len);
	bzero(buff, packet_len);
	pstPacket = (PS_PACKET_DATA)buff;
	pstPacket->type = TYPE_ACK_ACK;
	pstPacket->content = content;
	pstPacket->sn = cur_sn;
	pstPacket->data_len = 0;
	send_packet(buff, packet_len);
	free(buff);
	return 0;
}

int send_request_data_packet(unsigned char content)
{
	char *buff;
	PS_PACKET_DATA pstPacket;
	int packet_len;

	packet_len = sizeof(S_PACKET_DATA);
	buff = Malloc(packet_len);
	pstPacket = (PS_PACKET_DATA)buff;
	pstPacket->type = TYPE_REQUEST_DATA;
	pstPacket->content = content;
	pstPacket->sn = cur_sn;
	pstPacket->data_len = 0;
	send_packet(buff, packet_len);
	free(buff);
	return 0;
}

int recv_ack_packet(int timeout, int content, int syn_flag, int *err_no)
{
	char recv_buff[512];
	int ret;
	PS_PACKET_DATA pstPacket;
	time_t cur_time, start_time;

	cur_time = start_time = time(NULL);
	while(cur_time-start_time < timeout)
	{
		ret = recv_packet(recv_buff, sizeof(recv_buff), timeout-(cur_time-start_time));
		if (ret == 0)
		{
			err_msg("recv time out");
			*err_no = 0;
			return -1;
		}
		pstPacket = (PS_PACKET_DATA)recv_buff;
		if (pstPacket->sn==cur_sn && pstPacket->type==TYPE_ACK && pstPacket->content==content)
		{
			if (*pstPacket->data != ERR_CODE_OK)
			{
				*err_no = *pstPacket->data;
				return -1;
			}
			else
			{
				if (syn_flag)
					send_ack_ack_packet(content);
				return 0;
			}
		}
		else
		{
			cur_time = time(NULL);
		}
	}
	err_msg("recv the wrong packet!!");
	*err_no = 0;
	return -1;	
}

int recv_ack_data_packet(char *data, int data_len, int timeout, int content, int *err_no)
{
	char recv_buff[512];
	int ret;
	PS_PACKET_DATA pstPacket;
	time_t cur_time, start_time;

	cur_time = start_time = time(NULL);
	while(cur_time-start_time < timeout)
	{
		ret = recv_packet(recv_buff, sizeof(recv_buff), timeout-(cur_time-start_time));
		if (ret == 0)
		{
			err_msg("recv time out");
			*err_no = 0;
			return -1;
		}
		pstPacket = (PS_PACKET_DATA)recv_buff;
		if (pstPacket->sn==cur_sn && pstPacket->type==TYPE_ACK_DATA && pstPacket->content==content)
		{
			if (*pstPacket->data != ERR_CODE_OK)
			{
				*err_no = *pstPacket->data;
				return -1;
			}
			else
			{
				memcpy(data, pstPacket->data+4, pstPacket->data_len-4);
				return 0;
			}
		}
		else
		{
			cur_time = time(NULL);
		}
	}
	err_msg("recv the wrong packet!!");
	*err_no = 0;
	return -1;	
}

int syn_time()
{
	time_t cur_time;
	int ret;
	int err_no;
	int cnt;
	cnt = 5;
	while(--cnt)
	{
		cur_time = time(NULL);
		send_request_packet(CONTENT_TIME_SYN, (char *)&cur_time, sizeof(time_t));
		ret = recv_ack_packet(5, CONTENT_TIME_SYN, 0, &err_no);
		if (ret == 0)
			break;
		sleep(1);
	}
	if (cnt == 0)
		return -1;
	return 0;	
}


